package com.ccrfid.rmc6.service.sys;

import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.sys.AccountEntity;
import com.ccrfid.rmc6.entity.sys.AccountRoleRelation;
import com.ccrfid.rmc6.entity.sys.AccountView;
import com.ccrfid.rmc6.entity.sys.RoleEntity;
import com.ccrfid.rmc6.pojo.dto.sys.AccountDto;
import com.ccrfid.rmc6.repository.search.SearchCriteria;
import com.ccrfid.rmc6.repository.sys.AccountRepository;
import com.ccrfid.rmc6.repository.sys.AccountRoleRelationRepository;
import com.ccrfid.rmc6.repository.sys.AccountViewRepository;
import com.ccrfid.rmc6.repository.sys.RoleRepository;
import com.ccrfid.rmc6.util.Md5PasswordUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;

@Service
@Transactional
public class AccountServiceImpl implements AccountService {
    private static final Logger logger = LoggerFactory.getLogger(AccountServiceImpl.class);
    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private AccountViewRepository accountViewRepository;
    @Autowired
    private AccountRoleRelationRepository accountRoleRelationRepository;
    @Autowired
    private RoleRepository roleRepository;

    @Override
    public Page<AccountView> getAccountInfoPage(SearchCriteria criteria, Pageable pageable) {
        Page<AccountView> page = accountViewRepository.search(criteria, pageable);
        return page;
    }

    @Override
    public AccountDto getAccountInfo(Long accountId) {
        if (accountRepository.existsById(accountId)) {
            AccountDto accountDto = new AccountDto();
            AccountEntity accountEntity = accountRepository.getById(accountId);
            accountDto.setAccount(accountEntity);
            List<AccountRoleRelation> relationList = accountRoleRelationRepository.getAllByAccountId(accountId);
            if (relationList != null && !relationList.isEmpty()) {
                List<Long> idList = new ArrayList<>();
                for (AccountRoleRelation relation : relationList) {
                    idList.add(relation.getRoleId());
                }
                List<RoleEntity> roleList = roleRepository.getAllByIdIn(idList);
                accountDto.setRoleList(roleList);
            }
            return accountDto;
        }
        return null;
    }

    @Override
    public AccountEntity getAccountInfo(String userAccount) {
        return accountRepository.getByUserAccount(userAccount);
    }

    @Override
    public AccountEntity createAccount(AccountEntity entity) throws AppException {
        if (entity.getUserAccount() != null && accountRepository.existsByUserAccount(entity.getUserAccount())) {
            throw new AppException(Response.Status.CONFLICT.getStatusCode(),
                    CustomErrors.account_conflict.getCode(), CustomErrors.account_conflict.getReason(), "");
        }
        String rawPass = entity.getUserPasswd();
        entity.setUserPasswd(Md5PasswordUtil.encodePassword(rawPass, entity.getUserAccount()));
        return accountRepository.save(entity);
    }

    @Override
    public AccountEntity updateAccount(Long accountId, AccountEntity entity) throws AppException {
        if (!accountRepository.existsById(accountId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (!accountId.equals(entity.getId())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.different_args.getCode(), CustomErrors.different_args.getReason(), "");
        }
        if (accountRepository.existsByUserAccountAndAndIdNot(entity.getUserAccount(), accountId)) {
            throw new AppException(Response.Status.CONFLICT.getStatusCode(),
                    CustomErrors.account_conflict.getCode(), CustomErrors.account_conflict.getReason(), "");
        }
        AccountEntity accountEntity = accountRepository.getById(accountId);
        entity.setUserPasswd(accountEntity.getUserPasswd());
        return accountRepository.save(entity);
    }

    @Override
    public Boolean resetAccountPassword(Long accountId, String password) throws AppException {
        if (!accountRepository.existsById(accountId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        if (StringUtils.isEmpty(password)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.password_is_null.getCode(), CustomErrors.password_is_null.getReason(), "");
        }
        AccountEntity accountEntity = accountRepository.getById(accountId);
        accountEntity.setUserPasswd(Md5PasswordUtil.encodePassword(password, accountEntity.getUserAccount()));
        accountRepository.save(accountEntity);
        return true;
    }

    @Override
    public List<RoleEntity> getRoleList(Long accountId) {
        if (accountRepository.existsById(accountId)) {
            List<AccountRoleRelation> relationList = accountRoleRelationRepository.getAllByAccountId(accountId);
            if (relationList != null && !relationList.isEmpty()) {
                List<Long> idList = new ArrayList<>();
                for (AccountRoleRelation relation : relationList) {
                    idList.add(relation.getRoleId());
                }
                List<RoleEntity> roleList = roleRepository.getAllByIdIn(idList);
                return roleList;
            }
        }
        return null;
    }

    @Override
    public List<RoleEntity> updateRoleList(Long accountId, List<Long> roleIdList) throws AppException {
        if (!accountRepository.existsById(accountId)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.resource_not_found.getCode(), CustomErrors.resource_not_found.getReason(), "");
        }
        //内置管理员不能修改角色
        if (accountId.equals(1L)) {
            return getRoleList(accountId);
        }
        if (roleIdList != null && !roleIdList.isEmpty()) {
            List<AccountRoleRelation> relationList = accountRoleRelationRepository.getAllByAccountId(accountId);
            if (relationList != null && !relationList.isEmpty()) {
                for (AccountRoleRelation relation : relationList) {
                    if (!roleIdList.contains(relation.getRoleId())) {
                        accountRoleRelationRepository.deleteByAccountIdAndRoleId(accountId, relation.getRoleId());
                    }
                }
                for (Long roleId : roleIdList) {
                    if (!accountRoleRelationRepository.existsByAccountIdAndRoleId(accountId, roleId)) {
                        AccountRoleRelation relation = new AccountRoleRelation();
                        relation.setAccountId(accountId);
                        relation.setRoleId(roleId);
                        accountRoleRelationRepository.save(relation);
                    }
                }
            } else {
                for (Long roleId : roleIdList) {
                    AccountRoleRelation relation = new AccountRoleRelation();
                    relation.setAccountId(accountId);
                    relation.setRoleId(roleId);
                    accountRoleRelationRepository.save(relation);
                }
            }
        } else {
            accountRoleRelationRepository.deleteByAccountId(accountId);
        }
        return getRoleList(accountId);
    }

    @Override
    public int deleteAccounts(List<Long> idList) {
        int count = 0;
        for (Long id : idList) {
            if (!id.equals(1L) && accountRepository.existsById(id)) {
                //
                accountRoleRelationRepository.deleteByAccountId(id);
                //
                accountRepository.deleteById(id);

                count++;
            }
        }
        return count;
    }

    @Override
    public List<AccountEntity> getAccountListByPersonnelId(Long personnelId) {
        return accountRepository.getAllByPersonnelId(personnelId);
    }
}
